#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <termios.h>
#include <sys/msg.h>
#include <stdint.h>
#include <math.h>
#include <sys/select.h>
#include <time.h>  
#include <linux/input.h> 
#include <sys/wait.h> 
#include <net/if.h> 
#include <netinet/in.h> 
#include <netinet/tcp.h>
#include <net/if_arp.h> 
#include <arpa/inet.h>

#include "flyctl_net.h"
#include "common.h"
#include "pthread_mng.h"
#include "fly_server.h"
#include "msg_queue.h"
#include "com_util.h"


static FLYCTL_NET_ATTR g_flyctl_attr;
static int g_client_conn_status;
int time_out_first_flag = 1;
int first_conn_flg = 1;

int flyctl_net_get_wifi_conn_status()
{
	return g_client_conn_status;
}

int flyctl_net_get_wifi_conn_fd()
{
    return g_flyctl_attr.clientAttr.socketFd;
}

int flyctl_net_close()
{
	g_client_conn_status = 0;
    shutdown(g_flyctl_attr.clientAttr.socketFd, 2);
	close(g_flyctl_attr.clientAttr.socketFd);
    g_flyctl_attr.clientAttr.socketFd = -1;
	return SUCCESS;
} 

int flyctl_datacheck(char* buf,int len)
{
	if(!buf)
		return -1;

	if(buf[0] != 0x66 || buf[len-1] != 0x99)
		return -1;
	
	int i;
	char tmp;
	tmp = buf[1];
	for(i=2;i<len-2;i++)
		tmp^=buf[i];
	tmp&=0xFF;
	if(tmp == buf[len-2])
		return 0;
	else
		return -1;

}

int flyctl_net_send(int fd,unsigned char* buf,int len)
{
	if(!buf || fd < 0)
		return FAILURE;
	int ret;
	fd_set fds;
	int writeBytes;

	//PRINT_MSG(buf,len);
	//DEBUG_INFO("%s",buf);
	
	struct timeval timeout;
	timeout.tv_sec = 0;
	timeout.tv_usec = 300000;
	FD_ZERO(&fds);
	FD_SET(fd,&fds);
	
	ret = select(fd+1,NULL,&fds,NULL,&timeout);
	if(ret < 0)
	{
		DEBUG_INFO("select err");
		return FAILURE;
	}
	else if(ret == 0)
	{
		DEBUG_INFO("send select timeout");
		return FAILURE;
	}
	else{
		if(FD_ISSET(fd,&fds))
		{
			writeBytes = send(fd,buf,len,0);
			if(writeBytes <= 0)
			{
				DEBUG_INFO("send err");
				return FAILURE;
			}
		}
		
	}

	
	return SUCCESS;	

}

int flyctl_net_recv(unsigned char* buf,int len)
{
	if(!buf)
		return FAILURE;
	int ret;
	fd_set fds;
	int readBytes;
	char tmpbuf[64]={0};
	struct timeval timeout;

	timeout.tv_sec = 2;
	timeout.tv_usec = 0;
	if(time_out_first_flag)
	{
		timeout.tv_sec = 4;
		timeout.tv_usec = 0;
		time_out_first_flag = 0;
	}
	
	FD_ZERO(&fds);
	FD_SET(g_flyctl_attr.clientAttr.socketFd,&fds);
	ret = select(g_flyctl_attr.clientAttr.socketFd+1,&fds,NULL,NULL,&timeout);
	if(ret < 0)
	{
		DEBUG_ERR("select err");
		flyctl_net_close();
		return NET_STATUS_ERR;
	}
	else if(ret == 0)
	{
		DEBUG_INFO("recv select timeout,first client disconnect");
		flyctl_net_close();
		return NET_STATUS_DISCONNECT;
	}
	else{
		if(FD_ISSET(g_flyctl_attr.clientAttr.socketFd,&fds))
		{
			memset(tmpbuf,0,sizeof(tmpbuf));
			readBytes = recv(g_flyctl_attr.clientAttr.socketFd,tmpbuf,len,0);
			if(readBytes < 0)
			{
				DEBUG_ERR("recv err");
				flyctl_net_close();
				return NET_STATUS_ERR;
			}
			else if(readBytes == 0)
			{
				//==0 normal disconnect

				DEBUG_INFO("first client disconnect");
				flyctl_net_close();
				return NET_STATUS_DISCONNECT;
			}
			else if(readBytes > 0)
			{
				#if 0
				if(flyctl_datacheck(tmpbuf,len) < 0)
				{
					DEBUG_ERR("recv data check err\n");
					return NET_STATUS_DATA_ERR;
				}
				#endif
				memcpy(buf,tmpbuf,len);
				
			}

		}
		
	}
	
	return SUCCESS;
}

int flyctl_net_sys_synctoapp(unsigned char* buf,int len)
{
	static u8 serialNet = 0;
	if(!buf)
	{
		DEBUG_INFO("buf NULL");
		return FAILURE;
	}
	COM_BUF_S* ptrComBuf = (COM_BUF_S*)buf;
	MSG_NET_PROT_S stNetBuf;
	memset(&stNetBuf,0,sizeof(MSG_NET_PROT_S));
	
	stNetBuf.header = MSG_FIELD_HEADER;
	stNetBuf.serialNum = serialNet;
	stNetBuf.netBuff.cmd = ptrComBuf->cmd;
	stNetBuf.netBuff.serialNum = 0;
	memcpy(stNetBuf.netBuff.buf,ptrComBuf->buf,sizeof(ptrComBuf->buf));
	stNetBuf.dataCheck = 0x60;
	stNetBuf.tail = MSG_FIELD_TAIL;

	if(flyctl_net_send(g_flyctl_attr.clientAttr.socketFd,(u8*)&stNetBuf,sizeof(MSG_NET_PROT_S)) < 0)
	{
		DEBUG_INFO("reply buf err");
		return FAILURE;
	}
	serialNet++;
	return SUCCESS;
}

int getPeerMacbySocketFd( int sockfd, char *buf, char* localethname ) 
{ 
    int ret =0; 
    struct arpreq arpreq; 
    struct sockaddr_in dstadd_in; 
    socklen_t  len = sizeof( struct sockaddr_in ); 
    memset( &arpreq, 0, sizeof( struct arpreq )); 
    memset( &dstadd_in, 0, sizeof( struct sockaddr_in ));  
    if( getpeername( sockfd, (struct sockaddr*)&dstadd_in, &len ) < 0 ) 
    { 
       // perror("get peer name wrong, %s\n", strerror(errno) ); 
        return -1; 
    } 
    else 
    { 
        memcpy( ( struct sockaddr_in * )&arpreq.arp_pa, ( struct sockaddr_in * )&dstadd_in, sizeof( struct sockaddr_in )); 
        strcpy(arpreq.arp_dev, localethname); 
        arpreq.arp_pa.sa_family = AF_INET; 
        arpreq.arp_ha.sa_family = AF_UNSPEC; 
        if( ioctl( sockfd, SIOCGARP, &arpreq ) < 0 ) 
        { 
            //perror( "ioctl SIOCGARP wrong, %s\n", strerror(errno) ); 
            return -1; 
        } 
        else 
        { 
            unsigned char* ptr = (unsigned char *)arpreq.arp_ha.sa_data; 
            sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)); 
        } 
     } 
     return ret; 
}


int flyctl_net_accept()
{
	int clientsocket = -1;
	struct sockaddr_in clientaddr;
	socklen_t addrlen = sizeof(clientaddr);
	char addr1[16]={0};
	char addr2[16]={0};
	char mac[32]={0};
	
	memset(&clientaddr,0,addrlen);
	if((clientsocket=accept(g_flyctl_attr.servAttr.socketFd,(struct sockaddr*)&clientaddr,&addrlen)) < 0)
	{
		DEBUG_ERR("accept err");	
		return FAILURE;
	}

	DEBUG_INFO("flyctl have a client connect");

	#if 0
	memset(mac,0,sizeof(mac));
	getPeerMacbySocketFd(clientsocket,mac,"wlan0");
	DEBUG_INFO("first client mac:%s",mac);
	#endif

	memset(addr1,0,sizeof(addr1));
	memcpy(addr1,inet_ntoa(clientaddr.sin_addr),15);
	memset(addr2,0,sizeof(addr2));
	memcpy(addr2,inet_ntoa(g_flyctl_attr.clientAttr.sockAddr.sin_addr),15);

	if((first_conn_flg || ((!first_conn_flg)&&(!strcmp(addr1,addr2))))&&(g_client_conn_status==0))
	{
		DEBUG_INFO("first client ip:%s",inet_ntoa(clientaddr.sin_addr));
		g_flyctl_attr.clientAttr.socketFd = clientsocket;
		memcpy(&g_flyctl_attr.clientAttr.sockAddr,&clientaddr,addrlen);
		first_conn_flg = 0;

		g_client_conn_status = 1;
    
		return SUCCESS;
	}else{
		DEBUG_INFO("not first client,cannot control ");
		return FAILURE;
	}
	
}

int flyctl_net_init(int port)
{
	int reUseAddr=1;
	struct sockaddr_in ServerAddr;
	if((g_flyctl_attr.servAttr.socketFd=socket(AF_INET,SOCK_STREAM,0)) < 0)
	{
		 DEBUG_ERR("socket err");	
		 return FAILURE;
	}

	if(setsockopt(g_flyctl_attr.servAttr.socketFd,SOL_SOCKET,SO_REUSEADDR,&reUseAddr,sizeof(reUseAddr)) < 0)      
    	{     
        	DEBUG_ERR("Reusing ADDR failed");     
        	return FAILURE;	  
   	}   
	
	memset(&ServerAddr,0,sizeof(ServerAddr));
	ServerAddr.sin_family = AF_INET;
	ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	ServerAddr.sin_port = htons(port);
	if(bind(g_flyctl_attr.servAttr.socketFd,(struct sockaddr *)&ServerAddr,sizeof(ServerAddr)) < 0)
	{
		 DEBUG_ERR("bind err ");	
		 return FAILURE;
	}

	if(listen(g_flyctl_attr.servAttr.socketFd,MAXLINK) < 0)
	{
		 DEBUG_ERR("listen err ");	
		 return FAILURE;
	}

	return SUCCESS;
}

int flyctl_net_deinit()
{
	if(g_flyctl_attr.clientAttr.socketFd > 0)
		close(g_flyctl_attr.clientAttr.socketFd);
	return SUCCESS;
}                        